package com.startx.http.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import com.startx.core.tools.xml.XmlReader;
import com.startx.http.system.constant.Constants;
import com.startx.http.system.tool.CopyField;

@SuppressWarnings("unchecked")
public class BaseDao<T> {
	
	/**
	 * SQl xml 地址
	 */
	private String XML = Constants.SQL_MAPPER+"/"+getGenericClass().getSimpleName()+".xml";
	/**
	 * sql文件
	 */
	private Map<String,String> SQL = 
			XmlReader.parseXml(BaseDao.class.getResourceAsStream(XML));
	
	/**
	 * 命名参数查询
	 */
	@Inject
	private NamedParameterJdbcTemplate namedTemplate;
	/**
	 * 下标查询
	 */
	@Inject
	private JdbcTemplate jdbcTemplate;
	
	/**
	 * 获取jdbcTemplate
	 * @return
	 */
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
	
	/**
	 * 获取getNamedTemplate
	 * @return
	 */
	public NamedParameterJdbcTemplate getNamedTemplate() {
		return namedTemplate;
	}
	
	/**
	 * 命名参数
	 * 对象方式，单条更新或插入
	 * @param sql
	 * @param obj
	 */
	public void save(final String name,Object obj) {
		 SqlParameterSource paramSource = new BeanPropertySqlParameterSource(obj);
		 namedTemplate.update(SQL.get(name), paramSource); 
	}
	
	/**
	 * 字典方式，单条更新或插入
	 * @param sql
	 * @param obj
	 */
	public void save(final String name,Map<String,?> params) {
		 namedTemplate.update(SQL.get(name), params);  
	}
	
	/**
	 * 命名参数
	 * 对象方式，单条更新或插入
	 * @param sql
	 * @param obj
	 */
	public void update(final String name,Object obj) {
		 SqlParameterSource paramSource = new BeanPropertySqlParameterSource(obj);
		 namedTemplate.update(SQL.get(name), paramSource); 
	}
	
	/**
	 * 字典方式，单条更新或插入
	 * @param sql
	 * @param obj
	 */
	public void update(final String name,Map<String,?> params) {
		 namedTemplate.update(SQL.get(name), params);  
	}
	
	/**
	 * 命名参数
	 * 对象方式，批量更新或插入
	 * @param sql
	 * @param batchValues
	 */
	public void batchSave(final String name,List<?> batchValues) {
		
		if(batchValues.isEmpty()) return;
		
		SqlParameterSource[] paramSource = new SqlParameterSource[batchValues.size()];
		for (int i=0;i<batchValues.size();i++) {
			paramSource[i] = new BeanPropertySqlParameterSource(batchValues.get(i));
		}
		
		namedTemplate.batchUpdate(SQL.get(name), paramSource);
	}
	
	/**
	 * 字典方式，批量更新或插入
	 * @param sql
	 * @param batchValues
	 */
	public void batchSave(final String name,Map<String,?>[] batchValues) {
		namedTemplate.batchUpdate(SQL.get(name), batchValues);
	}
	
	/**
	 * 命名参数
	 * 对象方式，批量更新或插入
	 * @param sql
	 * @param batchValues
	 */
	public void batchUpdate(final String name,List<?> batchValues) {
		
		if(batchValues.isEmpty()) return;
		
		SqlParameterSource[] paramSource = new SqlParameterSource[batchValues.size()];
		for (int i=0;i<batchValues.size();i++) {
			paramSource[i] = new BeanPropertySqlParameterSource(batchValues.get(i));
		}
		
		namedTemplate.batchUpdate(SQL.get(name), paramSource);
	}
	
	/**
	 * 字典方式，批量更新或插入
	 * @param sql
	 * @param batchValues
	 */
	public void batchUpdate(final String name,Map<String,?>[] batchValues) {
		namedTemplate.batchUpdate(SQL.get(name), batchValues);
	}

	/**
	 * 存在?
	 */
	public boolean exist(final String name, final Object... args) {
		return jdbcTemplate.queryForObject(SQL.get(name), Long.class, args) > 0;
	}

	/**
	 * 执行sql
	 */
	public void execute(final String name, final Object... args) {
		jdbcTemplate.update(SQL.get(name), args);
	}

	/**
	 * 查询一组对象
	 */
	public List<T> list(final String name, final Object... args) {
		try {
			List<Map<String, Object>> dbResult = jdbcTemplate.queryForList(SQL.get(name), args);
			List<T> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				T target = getT();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			return result;
		} catch (DataAccessException e) {
			return new ArrayList<>();
		}
	}
	
	/**
	 * 查询一组对象
	 */
	public List<T> list(final String name,final Map<String,Object> param) {
		try {
			List<Map<String, Object>> dbResult = namedTemplate.queryForList(SQL.get(name), param);
			List<T> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				T target = getT();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			return result;
		} catch (DataAccessException e) {
			return new ArrayList<>();
		}
	}
	
	/**
	 * 查询一组对象
	 */
	public List<T> list(final String name) {
		try {
			List<Map<String, Object>> dbResult = jdbcTemplate.queryForList(SQL.get(name));
			List<T> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				T target = getT();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			return result;
		} catch (DataAccessException e) {
			return new ArrayList<>();
		}
	}
	
	/**
	 * 查询单个对象
	 */
	public T get(final String name, final Object... args) {
		try {
			T target = getT();
			Map<String, Object> source = jdbcTemplate.queryForMap(SQL.get(name),args);
			CopyField.copyMap2Obj(source, target);
			return target;
		} catch (DataAccessException e) {
			return null;
		}
	}
	
	/**
	 * 获取泛型类
	 * @return
	 */
	private Class<?> getGenericClass() {
		Type sType = getClass().getGenericSuperclass();
		Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
		Class<T> mTClass = (Class<T>) (generics[0]);
		return mTClass;
	}
	
	/**
	 * 获取泛型对象
	 * @return
	 */
	private T getT() {
		try {
			Type sType = getClass().getGenericSuperclass();
			Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
			Class<T> mTClass = (Class<T>) (generics[0]);
			return mTClass.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			return null;
		}
	}
	
	/**
	 * 查询一组对象
	 */
	public <N extends Object>List<N> list(final String name,final Class<?> clz,final Map<String,Object> param) {
		try {
			List<Map<String, Object>> dbResult = namedTemplate.queryForList(SQL.get(name), param);
			List<N> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				N target = (N) clz.newInstance();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			return result;
		} catch (InstantiationException | IllegalAccessException e) {
			return new ArrayList<>();
		}
	}
	
	/**
	 * 查询一组对象
	 */
	public <N extends Object>List<N> list(final String name,final Class<?> clz) {
		try {
			List<Map<String, Object>> dbResult = jdbcTemplate.queryForList(SQL.get(name));
			List<N> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				N target = (N) clz.newInstance();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			return result;
		} catch (InstantiationException | IllegalAccessException e) {
			return new ArrayList<>();
		}
		
	}
	
	/**
	 * 查询一组对象
	 */
	public <N extends Object>List<N> list(final String name,final Class<?> clz, final Object... args) {
		try {
			List<Map<String, Object>> dbResult = jdbcTemplate.queryForList(SQL.get(name), args);
			
			List<N> result = new ArrayList<>();
			for (Map<String,Object> source : dbResult) {
				N target = (N) clz.newInstance();
				if(target == null) {
					continue;
				}
				CopyField.copyMap2Obj(source, target);
				result.add(target);
			}
			
			return result;
		} catch (InstantiationException | IllegalAccessException e) {
			return new ArrayList<>();
		}
	}
	
	/**
	 * 查询自定义对象
	 */
	public <N extends Object> N get(final String name,Class<?> clz, final Object... args) {
		try {
			Object target = clz.newInstance();
			Map<String, Object> source = jdbcTemplate.queryForMap(SQL.get(name), args);
			CopyField.copyMap2Obj(source,target);
			return (N) target;
		} catch (DataAccessException | InstantiationException | IllegalAccessException e) {
			return null;
		}
	}
	
	/**
	 * 查询基本数据类型对象
	 */
	public <N extends Object> List<N> getList(final String name,final Class<?> clz, final Object... args) {
		try {
			return (List<N>) jdbcTemplate.queryForList(SQL.get(name),clz, args);
		} catch (DataAccessException e) {
			return null;
		}
	}
	
	/**
	 * 查询基本数据类型对象
	 */
	public <N extends Object> N getValue(final String name,final Class<?> clz, final Object... args) {
		try {
			return (N) jdbcTemplate.queryForObject(SQL.get(name),clz, args);
		} catch (DataAccessException e) {
			return null;
		}
	}
}
